package com.scs.application.modules.dept.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.ParamKeys;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.MatrApplyDemandDTO;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.PackTempletItem;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.service.PackTempletItemService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.base.util.MatrPassUtil;
import com.scs.application.modules.base.util.SingleService;
import com.scs.application.modules.cfg.utils.ParameterUtils;
import com.scs.application.modules.dept.dto.ApplyByPackTempDTO;
import com.scs.application.modules.dept.dto.ApplyItemDTO;
import com.scs.application.modules.dept.entity.*;
import com.scs.application.modules.dept.mapper.ApplyAutoMapper;
import com.scs.application.modules.dept.mapper.ApplyItemMapper;
import com.scs.application.modules.dept.mapper.ApplyMapper;
import com.scs.application.modules.dept.service.*;
import com.scs.application.modules.dept.util.UtilBudget;
import com.scs.application.modules.purchase.entity.Order;
import com.scs.application.modules.purchase.enums.PurchaseType;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.sys.security.UserPrincipal;
import com.scs.application.modules.wm.dto.StockGroupWarehouseMatrDTO;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.enums.LockBusType;
import com.scs.application.modules.wm.enums.StockLockType;
import com.scs.application.modules.wm.mapper.DistItemMapper;
import com.scs.application.modules.wm.mapper.DistMapper;
import com.scs.application.modules.wm.service.StockLockService;
import com.scs.application.modules.wm.service.StockService;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
@AllArgsConstructor
public class ApplyServiceImpl extends BaseServiceImpl<ApplyMapper, Apply> implements ApplyService {
    private final ApplyItemMapper applyItemMapper;
    private final DistMapper distMapper;
    private final DistItemMapper distItemMapper;
    private final ApplyItemService applyItemService;
    private final MatrMapper matrMapper;
    private final StockService stockService;
    private final StockLockService stockLockService;
    private final ApplyAutoMapper applyAutoMapper;
    private final PackTempletItemService packTempletItemService;
    private final DemandService demandService;
    private final DemandItemService demandItemService;
    private final MatrPassUtil matrPassUtil;

    @Override
    public boolean saveOrUpdate(Apply entity) {
        if (StringUtils.isBlank(entity.getBusKey())) {
            entity.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.DEPT_APPLY_KEY));
        }
        return super.saveOrUpdate(entity);
    }

    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        // applyItemMapper.delete(Wrappers.<ApplyItem>query().in("apply_id", idList));

        for (Serializable id : idList) {
            // 调用子表 执行库存解锁等逻辑
            List<ApplyItem> applyItems = applyItemMapper.selectList(Wrappers.<ApplyItem>query().select("id").eq("apply_id", id));
            applyItemService.removeCascadeByIds(applyItems.stream().map(o -> o.getId()).collect(Collectors.toList()));
        }
        return super.removeCascadeByIds(idList);
    }

    @Override
    protected void beforeHandleFlowChange(FlowContext flowContext, Apply entity) {
        super.beforeHandleFlowChange(flowContext, entity);
        String buttonKey = flowContext.getButtonKey();


        // 提交审核，不允许空明细提交
        if ("submit".equalsIgnoreCase(buttonKey)) {
            Integer count = applyItemMapper.selectCount(Wrappers.<ApplyItem>query().eq("apply_id", flowContext.getBusId()));
            if (count == null || count == 0) {
                throw new BusinessException("请添加明细后提交");
            }

            List<ApplyItem> applyItemList = applyItemMapper.selectList(Wrappers.<ApplyItem>query().eq("apply_id", flowContext.getBusId()));
			//由于有试剂的入库数量为小数，不允许请领小数
            for(ApplyItem applyItem:applyItemList){
                if (applyItem.getPackageQty() != Double.valueOf(applyItem.getPackageQty()).intValue()) {
                throw new BusinessException("提交失败，请领耗材包装数量必须为整数！");
            }
            }            applyItemList.forEach(ob -> {
                //单品数量*单品价格 是否等于 合计金额
                if (UtilNum.mul(ob.getSkuQty(), ob.getSkuPrice()) != ob.getAmount()) {
                    ob.setAmount(UtilNum.mul(ob.getSkuQty(), ob.getSkuPrice()));
                    //单品数量*单品价格 是否等于 合计金额
                    applyItemService.updateById(ob);
                }
            });

            // 不允许超库存清零
            if (!ParameterUtils.isAllowOverApply()) {
                List<ApplyItem> applyItemListApply = applyItemList.stream().filter(find -> "1".equals(find.getApplyType())).collect(Collectors.toList());
                if (applyItemListApply.size() > 0) {
                    List<String> matrIdList = applyItemListApply.stream().map(ApplyItem::getMatrId).distinct().collect(Collectors.toList());
                    List<StockGroupWarehouseMatrDTO> stockGroupWarehouseMatrDTOS = stockService.getListGroupByMatr(Wrappers.<Stock>query()
                            .in("matr_id", matrIdList).eq( "warehouse_id", entity.getWarehouseId()));
                    Map<String,List<ApplyItem>> itemListGroupByMatrId = applyItemListApply.stream().collect(Collectors.groupingBy(o -> o.getMatrId()));
                    Double skuQtyApply;
                    Double skuQtyDb;
                    for(String matrId: itemListGroupByMatrId.keySet()) {
                        skuQtyApply = itemListGroupByMatrId.get(matrId).stream().mapToDouble(ApplyItem::getSkuQty).sum();
                        skuQtyDb = stockGroupWarehouseMatrDTOS.stream()
                                .filter(stockGroupWarehouseMatrDTO -> matrId.equals(stockGroupWarehouseMatrDTO.getMatrId()))
                                .mapToDouble(StockGroupWarehouseMatrDTO::getSkuQtyUseApply).sum();
                        if (skuQtyApply > skuQtyDb) {
                            BusinessException.throwValidFail(
                                    "商品申请单品数量已超过库存数量，商品:%s,申请单品数量:%s，可用单品数量:%s",
                                    applyItemListApply.stream().filter(find2 -> find2.getMatrId().equals(matrId)).findFirst().get().getMatrName(),
                                    skuQtyApply,
                                    skuQtyDb
                            );
                        }
                    }
                }
            }

            final double[] amountDtl = {0};
            applyItemList.stream().forEach(item -> amountDtl[0] = UtilNum.sum(amountDtl[0], item.getAmount()));
            Apply applyDb = this.getById(entity.getId());
            if (amountDtl[0] != applyDb.getAmount()) {
                applyDb.setAmount(amountDtl[0]);
                this.updateById(applyDb);
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    protected void afterHandleFlowChange(FlowContext flowContext, Apply entity) {
        super.afterHandleFlowChange(flowContext, entity);
        //作废
        if (flowContext.isCloseNode()){
            flowContext.setHandledMsg(this.closeMain(flowContext.getBusEntity(),null,flowContext.getComment()));
        }

        String buttonKey = flowContext.getButtonKey();
        if ("pass".equalsIgnoreCase(buttonKey) || "demand_submit".equalsIgnoreCase(buttonKey)) {
            Apply apply = flowContext.getBusEntity();

            List<ApplyItem> applyItems = applyItemMapper.selectList(Wrappers.<ApplyItem>query().eq("apply_id", apply.getId()));
            if (applyItems.isEmpty()) {
                throw new BusinessException("请购明细为空，转换单据失败");
            }
            //是否禁用耗材校验 - 请领流程
            matrPassUtil.ckeckMatrPass("apply", applyItems.stream().map(ApplyItem::getMatrId).collect(Collectors.toList()));
            //预算控制检查
            UtilBudget.checkBudgetControl(apply.getDeptId(),applyItems);

            //需要转换为二级库请领
            List<ApplyItem> autoApplyItems = applyItems.stream().filter(item -> item.getApplyType().equals(GlobalConsts.applyTypeOfApply)).collect(Collectors.toList());
            if (autoApplyItems != null && autoApplyItems.size() > 0) {
                convertApplyToAuto(autoApplyItems, apply);
            }
            //需要转换为二级库需求
            List<ApplyItem> autoDemandItems = applyItems.stream().filter(item -> !item.getApplyType().equals(GlobalConsts.applyTypeOfApply)).collect(Collectors.toList());
            if (autoDemandItems != null && autoDemandItems.size() > 0) {
                convertApplyToDemand(autoDemandItems, apply, buttonKey);
            }
            flowContext.setHandledMsg("下单成功");
        }
    }

    /**
     * 将请领需求转换为需求
     */
    private void convertApplyToDemand(List<ApplyItem> autoDemandItems, Apply apply, String buttonKey) {
        Demand demand = new Demand();
        BeanUtils.copyProperties(apply, demand);
        demand.setBusKey(null)
                .setRefId(apply.getId()).setRefTable(GlobalConsts.AUTO_REF_TABLE_APPLY)
                .setRemark(UtilCommon.getStringPre(String.format("请领备注：%s，请领单：%s ",UtilCommon.getStr(apply.getRemark(),"无"), apply.getBusKey()), 180))
                .setFlowStatus("start")
                .setId(null);

        if (!demandService.saveOrUpdate(demand)) {
            throw new BusinessException("转换需求失败");
        }

        List<DemandItem> demandItems = Lists.newArrayListWithCapacity(autoDemandItems.size());
        for (ApplyItem applyItem : autoDemandItems) {
            DemandItem demandItem = new DemandItem();
            BeanUtils.copyProperties(applyItem, demandItem);
            demandItem.setDemandId(demand.getId()).setApplyItemId(applyItem.getId())
                    .setId(null);
            demandItem.setRemark(UtilCommon.getStringPre(String.format("请领备注：%s，请领单：%s ",UtilCommon.getStr(applyItem.getRemark(),"无"), apply.getBusKey()), 180));
            demandItems.add(demandItem);
        }
        demandItemService.saveBatch(demandItems);

        //根据通用参数apply_demand_audit判断1：直接审核通过 0：制单
        if ("1".equals(ParameterUtils.getString((ParamKeys.APPLY_DEMAND_AUDIT)))) {
            //是否禁用耗材校验 - 自动：请领->需求
            matrPassUtil.ckeckMatrPass("demand", autoDemandItems.stream().map(ApplyItem::getMatrId).collect(Collectors.toList()));
            demand.setFlowStatus("end");
            demandService.saveOrUpdate(demand);
            List<Order> orders = demandService.convertDemandToOrders(demand);

            log.info("需求计划转换完成，共生成{}个采购订单", orders.size());
            log.info("采购单号分别为：{}", orders.stream().map(o -> o.getBusKey()).collect(Collectors.joining(",")));
        }

        for (ApplyItem applyItem : autoDemandItems) {
            //更新需求明细状态
            CommonService.updateApplyItemStatus(applyItem.getId(), false, null);
        }
    }

    private void convertApplyToAuto(List<ApplyItem> autoApplyItems, Apply apply) {
        boolean applyLock = ParameterUtils.isApplyLockStock(); // 请领是否锁库存
        boolean isAllowOverApply = ParameterUtils.isAllowOverApply(); //是否允许0库存请领
        List<ApplyAuto> saveList = new ArrayList<>();

        for (ApplyItem applyItem : autoApplyItems) {
            Matr matr = matrMapper.selectById(applyItem.getMatrId());

            String warehouseId = apply.getWarehouseId();
            Double availableStock = stockService.getAvailableStock(warehouseId, matr.getId(), StockLockType.VIRTUAL);
            if (applyLock && !matr.getFlagOmoc()) { //必须是锁虚拟库存并且配送的才会去锁
                //库位不足并且不可以零库存请领
                if (availableStock < applyItem.getSkuQty() && !isAllowOverApply) {
                    throw new BusinessException("%s库存不足，请修改你的请领计划", matr.getName());
                }
                //有库存
                if (availableStock > 0) {//如果有效库存<申请库存 锁定有效库存, 否则正常锁库存
                    stockLockService.virtualLock(LockBusType.APPLY, applyItem.getId(), warehouseId, applyItem.getMatrId(), availableStock < applyItem.getSkuQty() ? availableStock : applyItem.getSkuQty());
                }
            }
            if (availableStock < 0){
                availableStock = 0d;
            }

            // 耗材按照一物一码转配送/调拨需求，试剂按照库存试剂转配送/调拨需求
            boolean isReagent = PurchaseType.REAGENT.getKey().equals(matr.getBaseType());
            boolean transfer = matr.getFlagOmoc();
            String settlement = matr.getFlagOmoc() ? GlobalConsts.SettlementType.usedSettlement : GlobalConsts.SettlementType.outSettlement;
            if (isReagent) {
                transfer = matr.getFlagStockReagent();
                settlement = matr.getFlagStockReagent() ? GlobalConsts.SettlementType.usedSettlement : GlobalConsts.SettlementType.outSettlement;
            }

            ApplyAuto applyAuto = new ApplyAuto();
            BeanUtils.copyProperties(applyItem, applyAuto);
            applyAuto.setId(null);
            applyAuto.setSettlementType(settlement)
                    .setRefType(GlobalConsts.APPLYAUTO_REFTYPE_AUTO_APPLY)
                    .setRefTable(GlobalConsts.AUTO_REF_TABLE_APPLY)
                    .setBusKey(apply.getBusKey())
                    .setMatrName(applyItem.getMatrName())
                    .setDeptId(apply.getDeptId())
                    .setDeptName(apply.getDeptName())
                    .setWarehouseId(apply.getWarehouseId())
                    .setWarehouseName(apply.getWarehouseName())
                    .setApplyWarehouseId(apply.getApplyWarehouseId())
                    .setApplyWarehouseName(apply.getApplyWarehouseName())
                    .setMatrSpec(applyItem.getMatrSpec())
                    .setRefApplyItemId(applyItem.getId())
                    .setSkuUnit(applyItem.getSkuUnit())
                    .setGmtApply(apply.getFlowModified())
                    .setSkuQtyApply(applyItem.getSkuQty())
                    .setSkuQtyApply0(applyItem.getSkuQty())
                    .setSkuQtyStock(availableStock)
                    .setSkuQtyDaily(0.0)
                    .setSkuQtySafety(0.0)
                    .setRequiredUnit(applyItem.getPackageUnit())
                    .setGmtUpdate(LocalDateTime.now())
                    .setFlagTransfer(transfer)
                    .setRemark(apply.getRemark())
                    .setDemandLevel(applyItem.getDemandLevel())
                    .setApplyType(GlobalConsts.applyTypeOfApply)
                    .setMatrId(applyItem.getMatrId()).setSupplierId(matr.getSupplierId())
                    .setSupplierName(matr.getSupplierName())
                    .setMfgName(matr.getMfgName())
                    .setMfgId(matr.getMfgId())
                    .setDemandPackageQty(applyItem.getSkuQty()/applyItem.getPackageRate())
                    .setDemandPackageQty0(applyItem.getSkuQty()/applyItem.getPackageRate())
                    .setSkuPrice(matr.getSkuPrice())
                    .setFlagOmoc(matr.getFlagOmoc())
                    .setFlagGys(matr.getFlagGys())
                    .setApplyUser(apply.getFlowModifier())
                    .setRequiredRate(applyItem.getPackageRate())
                    .setReagentTeamId(isReagent ? apply.getReagentTeamId() : null)
                    .setBillPackageUnit(applyItem.getPackageUnit()).setBillPackageRate(applyItem.getPackageRate()).setBillPackageQty(0d)
                    ;
            saveList.add(applyAuto);
        }

        // 批量保存明细
        this.saveBatch(ApplyAuto.class, saveList, 100);
        Apply entityDb = baseMapper.selectById(apply.getId());
        //推送消息给运营管理员
        CommonService.pushMessageRole("科室请领:" + entityDb.getDeptName(), "" + autoApplyItems.size() + "条请领明细", "admin_yy");

    }

    private Dist convertApplyToDist(Apply apply) {
        String demandId = apply.getId();

        List<ApplyItem> applyItems = applyItemMapper.selectList(Wrappers.<ApplyItem>query().eq("apply_id", demandId));
        if (applyItems.isEmpty()) {
            throw new BusinessException("请购明细为空，转换配送单失败");
        }

        Dist dist = new Dist();

        dist.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.WM_DIST_KEY))
                .setBusDate(new Date()).setBusUser("待配置")
                .setApplyId(apply.getId()).setApplyKey(apply.getBusKey()).setApplyDate(apply.getBusDate())
                .setDeptId(apply.getDeptId()).setDeptName(apply.getDeptName())
                .setWarehouseId(apply.getWarehouseId()).setWarehouseName(apply.getWarehouseName())
                .setAmount(applyItems.stream().mapToDouble(o -> o.getAmount()).sum())
                .setRemark(String.format("由科室请领单%s转换而来", apply.getBusKey()));
        distMapper.insert(dist);


        for (ApplyItem applyItem : applyItems) {
            DistItem distItem = new DistItem();
            BeanUtils.copyProperties(applyItem, distItem);
            distItem.setId(null);
            distItem.setDistId(dist.getId()).setApplyItemId(applyItem.getId())
                    .setMatrId(applyItem.getMatrId()).setMatrName(applyItem.getMatrName()).setMatrSpec(applyItem.getMatrSpec())
                    .setPackageUnit(applyItem.getPackageUnit()).setPackageRate(applyItem.getPackageRate()).setPackageQty(applyItem.getPackageQty())
                    .setSkuUnit(applyItem.getSkuUnit()).setSkuPrice(applyItem.getSkuPrice()).setSkuQty(applyItem.getSkuQty())
                    .setPickedSkuQty(0.0)
                    .setAmount(applyItem.getAmount())
                    .setRemark(String.format("由科室请领单%s转换而来", apply.getBusKey()));
            distItemMapper.insert(distItem);
        }

        return dist;
    }

    @Override
    public List<ApplyItemDTO> findDeptApply() {
//        Date beginDate = DateUtils.parse(DateFormatUtils.format(DateUtils.getFirstDayOfWeek(new Date()), "yyyy-MM-dd 00:00:00"));
        return this.baseMapper.findDeptApply(null);
    }

    @Override
    public Integer findThisWeekDeptApplyCount() {
        Date beginDate = DateUtils.parse(DateFormatUtils.format(DateUtils.getFirstDayOfWeek(new Date()), "yyyy-MM-dd 00:00:00"));
        Integer count = this.baseMapper.selectCount(Wrappers.<Apply>query().gt("gmt_create", beginDate));
        return count;
    }

    /**
     * 根据模板添加请领耗材信息
     *
     * @param applyByPackTempDTO
     * @return
     */
    public boolean addByTemp(ApplyByPackTempDTO applyByPackTempDTO) {
        if (applyByPackTempDTO.getPackTemplets() == null || applyByPackTempDTO.getPackTemplets().size() == 0) {
            throw new BusinessException("没有选择任何模板");
        }

        List<String> packTempletIds = applyByPackTempDTO.getPackTemplets().stream().map(item -> item.getId()).collect(Collectors.toList());
        List<PackTempletItem> packTempletItems = packTempletItemService.list(
                new QueryWrapper<PackTempletItem>().in("pack_templet_id", packTempletIds));

        List<ApplyItem> applyItemList = Lists.newArrayList();
        packTempletItems.forEach(item -> {
            ApplyItem applyItem = new ApplyItem();
            BeanUtils.copyProperties(item, applyItem);
            applyItem.setId(null);
            applyItem.setPackageRate(item.getPackageQty() / item.getSkuQty());
            applyItem.setSkuPrice(item.getAmount() / item.getSkuQty());
            applyItem.setApplyId(applyByPackTempDTO.getApplyId());
            applyItemList.add(applyItem);
        });
        applyItemService.saveBatch(applyItemList);
        return true;
    }

    /**
     * @Description：科室请领单（或明细）作废
     * @param itemId 明细id 传为明细作废，不传为整单作废
     *
     * 采购订单的状态  非 end、confirm
     *
     * 1、采购订单明细表增加 作废字段  flag_close 【默认是： 0：未作废】,close_remark   ，采购明细列表也显示这俩字段
     * 2、请领需求明细作废的时候
     *         找到对应采购订单明细   进行作废
     *          如果对应采购订单只有这一条明细，同时作废主单据
     *
     * 3、采购订单推送的时候
     *      明细筛选条件，在原有的条件基础上增加条件  flag_close != 1
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String closeMain(Apply apply,String itemId, String remark) {
        remark = "科室发起作废,"+UtilCommon.getStringPre(UtilCommon.getStr(remark,"无原因"),180);
        ApplyItem applyItem = null;
        String type;
        List<ApplyItem> applyItems;
        if (StringUtils.isBlank(itemId)) { //作废整单
            type="整单";
            applyItems = applyItemMapper.selectList(Wrappers.<ApplyItem>query().eq("apply_id", apply.getId()).eq("is_close",false));
        }else { //作废明细
            type="明细";
            applyItem = applyItemMapper.selectById(itemId);
            if (applyItem == null) throw new  BusinessException("%s作废失败，该请领明细已被删除",type);
            if (applyItem.getIsClose()) throw new  BusinessException("%s作废失败，该请领明细已作废，请刷新",type);
            applyItems = Arrays.asList(applyItem);
            apply = this.getById(applyItem.getApplyId());
        }
        if (apply == null ) throw new BusinessException("%s作废失败，该请领需求单已被删除",type);

        //整单作废是流程操作，判断在流程操作时已有判断
        if (StringUtils.isNotBlank(itemId) && apply.getFlowStatus().equals(GlobalConsts.FLOW_CLOSE_VALUE) ) throw new BusinessException("%s作废失败，该请领需求单已被作废",type);
        if (applyItems == null || applyItems.size() < 1) { //空单据，直接作废
            //作废请领主单据
            apply.setFlowStatus(GlobalConsts.FLOW_CLOSE_VALUE).setFlowCloseRemark(remark);
            this.updateById(apply);
            this.addFlowLogBatch(Arrays.asList(apply), remark,null);
            return type+"作废成功";
        };
        StringBuilder msg = new StringBuilder(type+"作废成功");
        List<String> itemIds = applyItems.stream().map(s -> s.getId()).collect(Collectors.toList());
        List<ApplyAuto> applyAutos = null;
        List<Dist> distList=null;
        List<Transfer> transferList=null;
        List<Demand> demandList= null;
        List<DemandSum> demandSumList=null;
        List<Order> orderList=null;

        //2 请领类
        applyAutos = SingleService.inst.applyAutoService.listWithHistory(Wrappers.<ApplyAuto>query().in("ref_apply_item_id",itemIds));
        if (applyAutos != null && applyAutos.size() > 0) {
            List<String> refIds = applyAutos.stream().filter(applyAutoTmp1 -> StringUtils.isNotBlank(applyAutoTmp1.getRefId()))
                    .map(s -> s.getRefId()).collect(Collectors.toList());
            if (refIds !=null && refIds.size() > 0){

                //21、配送单校验
                distList = SingleService.inst.distService.list(Wrappers.<Dist>query().in("id",refIds));
                if (distList != null && distList.size() > 0 ){
                    //已响应的配送单只要有一个非开始状态 则不允许作废
                    List<Dist> distAuditList = distList.stream().filter(dist -> StringUtils.isNotBlank(dist.getFlowStatus()) && !GlobalConsts.FLOW_START_VALUE.equals(dist.getFlowStatus())).collect(Collectors.toList());
                    if (distAuditList != null && distAuditList.size() > 0)
                        throw  new BusinessException(
                                "%s作废失败，以下配送单已在审核中<br>%s",
                                type,
                                StringUtils.join(distAuditList.stream().map(obTmp -> obTmp.getBusKey() ).collect(Collectors.toList()), ",")
                        );


                    //已响应的配送单如果包含其他明细，不允许作废
                    List<String> idList = SingleService.inst.distItemService.list(Wrappers.<DistItem>query().in("dist_id",distList.stream().map(Dist::getId).collect(Collectors.toList())).notIn("ifnull(apply_item_id,'')",itemIds))
                            .stream().map(DistItem::getDistId).distinct().collect(Collectors.toList());
                    if (idList != null && idList.size() > 0){
                        throw  new BusinessException(
                                "%s作废失败，以下配送单已添加其他配送明细<br>%s",
                                type,
                                StringUtils.join(distList.stream().filter(obTmp -> idList.contains(obTmp.getId())).map(obTmp -> obTmp.getBusKey()).collect(Collectors.toList()), ",")
                        );
                    }

                }

                //22、调拨单校验
                transferList = SingleService.inst.transferService.list(Wrappers.<Transfer>query().in("id",refIds));
                if (transferList != null && transferList.size() > 0 )      {

                    //已响应的调拨单只要有一个非开始状态 则不允许作废
                    List<Transfer> transferAuditList = transferList.stream().filter(transfer -> StringUtils.isNotBlank(transfer.getFlowStatus()) && !GlobalConsts.FLOW_START_VALUE.equals(transfer.getFlowStatus())).collect(Collectors.toList());
                    if (transferAuditList != null && transferAuditList.size() > 0)
                        throw  new BusinessException(
                                "%s作废失败，以下调拨单已在审核中<br>%s",
                                type,
                                StringUtils.join(transferAuditList.stream().map(obTmp -> obTmp.getBusKey() ).collect(Collectors.toList()), ",")
                        );

                    //已响应的调拨单如果包含其他明细，不允许作废
                    List<String> idList = SingleService.inst.transferDemandService.list(Wrappers.<TransferDemand>query().in("transfer_id",transferList.stream().map(Transfer::getId).collect(Collectors.toList())).notIn("ifnull(ref_apply_item_id,'')",itemIds))
                            .stream().map(TransferDemand::getTransferId).distinct().collect(Collectors.toList());
                    if (idList != null && idList.size() > 0){
                        throw  new BusinessException(
                                "%s作废失败，以下调拨单已添加其他调拨明细<br>%s",
                                type,
                                StringUtils.join(transferList.stream().filter(obTmp -> idList.contains(obTmp.getId())).map(obTmp -> obTmp.getBusKey()).collect(Collectors.toList()), ",")
                        );
                    }
                }

            }
        }

        //3 需求类

        if (StringUtils.isBlank(itemId)) { //作废整单
            demandList = demandService.list(Wrappers.<Demand>query().eq("ref_id",apply.getId()));
        }else {
            DemandItem demandItem = SingleService.inst.demandItemService.getOne(Wrappers.<DemandItem>query().eq("apply_item_id",itemId));
            if (demandItem != null) {
                demandList = new ArrayList<Demand>();
                demandList.add(demandService.getById(demandItem.getDemandId()));
            };
        }
        if (demandList != null && demandList.size() > 0 ){
            List<String> demandIds = demandList.stream().map(demand -> demand.getId()).collect(Collectors.toList());

            //31、需求单校验
            if (!"1".equals(ParameterUtils.getString((ParamKeys.APPLY_DEMAND_AUDIT)))) {
                //已响应的需求计划单只要有一个非开始状态 则不允许作废
                List<Demand> demandAuditList = demandList.stream().filter(obTmp -> StringUtils.isNotBlank(obTmp.getFlowStatus()) && !GlobalConsts.FLOW_START_VALUE.equals(obTmp.getFlowStatus())).collect(Collectors.toList());
                if (demandAuditList != null && demandAuditList.size() > 0)
                    throw  new BusinessException(
                            "%s作废失败，以下需求计划单已在审核中<br>%s",
                            type,
                            StringUtils.join(demandAuditList.stream().map(obTmp -> obTmp.getBusKey() ).collect(Collectors.toList()), ",")
                    );

                //已响应的需求计划单单如果包含其他明细，不允许作废
                List<String> idList = SingleService.inst.demandItemService.list(Wrappers.<DemandItem>query().in("demand_id",demandIds).notIn("ifnull(apply_item_id,'')",itemIds))
                        .stream().map(DemandItem::getDemandId).distinct().collect(Collectors.toList());
                if (idList != null && idList.size() > 0){
                    throw  new BusinessException(
                            "%s作废失败，以下需求计划单已添加其他明细<br>%s",
                            type,
                            StringUtils.join(demandList.stream().filter(obTmp -> idList.contains(obTmp.getId())).map(obTmp -> obTmp.getBusKey()).collect(Collectors.toList()), ",")
                    );
                }
            }

            //32、需求汇总校验
            demandSumList = SingleService.inst.demandSumService.ListWithItem(Wrappers.<DemandSum>query().in("demand_id",demandIds));
            if (demandSumList != null && demandSumList.size() > 0 ){
                //已响应的需求汇总单只要有一个非开始状态 则不允许作废
                List<DemandSum> demandSumAuditList = demandSumList.stream().filter(demandSum -> StringUtils.isNotBlank(demandSum.getFlowStatus()) && !GlobalConsts.FLOW_START_VALUE.equals(demandSum.getFlowStatus())).collect(Collectors.toList());
                if (demandSumAuditList != null && demandSumAuditList.size() > 0)
                    throw  new BusinessException(
                            "%s作废失败，以下需求汇总单已在审核中<br>%s",
                            type,
                            StringUtils.join(demandSumAuditList.stream().map(obTmp -> obTmp.getBusKey() ).collect(Collectors.toList()), ",")
                    );

                //已响应的需求汇总单如果包含其他明细，不允许作废
                List<String> idList = SingleService.inst.demandSumItemService.list(Wrappers.<DemandSumItem>query().in("demand_sum_id",demandSumList.stream().map(DemandSum::getId).collect(Collectors.toList())).notIn("demand_id",demandIds))
                        .stream().map(DemandSumItem::getDemandSumId).distinct().collect(Collectors.toList());
                if (idList != null && idList.size() > 0){
                    throw  new BusinessException(
                            "%s作废失败，以下需求汇总单已添加其他需求明细<br>%s",
                            type,
                            StringUtils.join(demandSumList.stream().filter(obTmp -> idList.contains(obTmp.getId())).map(obTmp -> obTmp.getBusKey()).collect(Collectors.toList()), ",")
                    );
                }
            }

            //33、采购订单校验
            orderList = SingleService.inst.orderService.list(Wrappers.<Order>query().in("ref_id", demandIds));
            if (orderList != null && orderList.size() > 0 ){
                //已响应的采购单只要有一个非开始状态 则不允许作废-->采购订单的状态  非 end、confirm状态时允许作废
                List<Order> orderAuditList = orderList.stream().filter(order -> StringUtils.isNotBlank(order.getFlowStatus()) && (GlobalConsts.FLOW_END_VALUE.equals(order.getFlowStatus())
                        || GlobalConsts.FLOW_CONFIRM_VALUE.equals(order.getFlowStatus())
                        || GlobalConsts.FLOW_SUBMIT_VALUE.equals(order.getFlowStatus()))).collect(Collectors.toList());
                if (orderAuditList != null && orderAuditList.size() > 0)
                    throw  new BusinessException(
                            "%s作废失败，以下采购订单已审核通过<br>%s",
                            type,
                            StringUtils.join(orderAuditList.stream().map(distTmp -> distTmp.getBusKey() ).collect(Collectors.toList()), ",")
                    );

                //已响应的采购单如果包含其他明细，不允许作废
                /*List<String> idList = SingleService.inst.orderItemService.list(Wrappers.<OrderItem>query().in("order_id",orderList.stream().map(Order::getId).collect(Collectors.toList())).notIn("ifnull(apply_item_id,'')",itemIds))
                        .stream().map(OrderItem::getOrderId).distinct().collect(Collectors.toList());
                if (idList != null && idList.size() > 0){
                    throw  new BusinessException(
                            "%s作废失败，以下采购订单已添加其他采购明细<br>%s",
                            type,
                            StringUtils.join(orderList.stream().filter(obTmp -> idList.contains(obTmp.getId())).map(obTmp -> obTmp.getBusKey()).collect(Collectors.toList()), ",")
                    );
                }*/
            }
        }

        if (StringUtils.isBlank(itemId)) { //作废整单
            //作废请领主单据
            apply.setFlowStatus(GlobalConsts.FLOW_CLOSE_VALUE).setFlowCloseRemark(remark);
            this.updateById(apply);

            //作废请领明细
            applyItemMapper.update(null,Wrappers.<ApplyItem>update().in("id",itemIds).set("is_close", 1));
        }else { //作废明细
            String dtlMsg = applyItem.getResponseStatusText();
            if (StringUtils.isNotBlank(dtlMsg)) {
                dtlMsg = dtlMsg+"<br>" + remark;
            } else {
                dtlMsg = remark;
            }
            Integer count = applyItemMapper.selectCount(Wrappers.<ApplyItem>query().eq("apply_id", apply.getId()).eq("is_close",false));

            applyItemMapper.update(null,Wrappers.<ApplyItem>update().in("id",itemIds).set("is_close", 1).set("response_status_text", dtlMsg));
            if (count != null && count == 1) { //当前为最后一条明细作废时，也进行整单作废
                //作废请领主单据
                apply.setFlowStatus(GlobalConsts.FLOW_CLOSE_VALUE).setFlowCloseRemark(remark);
                this.updateById(apply);
                this.addFlowLogBatch(Arrays.asList(apply), remark,null);
                msg.append("，当前为最后一条明细，已进行整单作废操作");
            }

        }


        //作废请领需求记录
        if (applyAutos != null && applyAutos.size() > 0) {
            SingleService.inst.applyAutoService.respondClose(applyAutos,remark);
            msg.append("<br>作废请领需求记录："+applyAutos.size());
        }

        //作废配送记录
        if (distList != null && distList.size() > 0) {
            SingleService.inst.distService.closeBatch(distList, remark,GlobalConsts.FLOW_START_VALUE );
            msg.append("<br>作废配送单据："+distList.size());
        }

        //作废调拨记录
        if (transferList != null && transferList.size() > 0) {
            SingleService.inst.transferService.closeBatch(transferList, remark,GlobalConsts.FLOW_START_VALUE );
            msg.append("<br>作废调拨单据："+transferList.size());
        }

        //作废需求计划记录
        if (demandList != null && demandList.size() > 0) {
            demandService.closeBatch(demandList, remark, null);
            msg.append("<br>作废需求计划单据："+demandList.size());
        }

        //作废需求计划汇总记录
        if (demandSumList != null && demandSumList.size() > 0) {
            SingleService.inst.demandSumService.closeBatch(demandSumList, remark,GlobalConsts.FLOW_START_VALUE );
            msg.append("<br>作废需求计划汇总单据："+demandSumList.size());
        }

        //作废采购订单记录
        if (orderList != null && orderList.size() > 0) {
            List<String> orderIdList = orderList.stream().map(order -> order.getId()).collect(Collectors.toList());
            SingleService.inst.orderService.closeOrder(orderIdList, itemIds ,remark,ParameterUtils.spd.getAllowCloseAfterDelivered(), UserUtils.currentUser().getName() );
            SingleService.inst.orderService.addFlowLogBatch(orderList, remark,null);
            msg.append("<br>作废采购订单单据："+orderList.size());
        }
        return msg.toString();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String closeItem(String itemId, String remark) {
        return this.closeMain(null,itemId,remark);
    }
    @Override
    public RestResult copyApplyAndItems(String applyId){
        RestResult result = RestResult.ok("操作成功");
        Apply apply = this.getById(applyId);
        if (null == apply || apply.getIsClose()) {
            result = RestResult.error("操作失败,无法获取可用的数据");
            return result;
        }
        List<ApplyItem> items = applyItemMapper.selectListWithoutDisabled(Wrappers.<ApplyItem>query().eq("apply_id", applyId).ne("is_close", true));
        if (items.isEmpty()) {
            result = RestResult.error("操作失败,无法获取可用的数据");
            return result;
        }
        UserPrincipal nowUser  = UserUtils.currentUser();
        Double amount = items.stream().mapToDouble(applyItem -> applyItem.getAmount()).sum();
        apply.setId(null);
        apply.setRemark(apply.getRemark() + " -- 从请领单号：" + apply.getBusKey() + "复制而来").setAmount(amount);
        apply.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.DEPT_APPLY_KEY)).setBusDate(new Date()).setBusUser(nowUser.getName());
        apply.setFlagPrint(false).setFlowStatus("start").setFlowModifier(nowUser.getName());
        this.save(apply);

        List<ApplyItem> newItems = new ArrayList<>(items.size());
        items.stream().forEach(applyItem -> {
            applyItem.setApplyId(apply.getId());
            applyItem.setId(null);
            applyItem.setCreator(nowUser.getCode()).setModifier(nowUser.getCode()).setGmtCreate(LocalDateTime.now()).setGmtModified(LocalDateTime.now());
            newItems.add(applyItem);
        });
        applyItemService.saveBatch(newItems);
        result.setData(apply);
        return result;
    }
}
